#ifndef Container_First
#define Container_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Iterator.h"
#include "Object.h"

extern const char
	*cWarningActiveIterator,
	*cWarningNullArgument;

const int
	cContainerInitCap= 16;

const bool
	cIterForward= TRUE,
	cIterBackward= !cIterForward;
		
//---- Container ---------------------------------------------------------------

class Container : public Object {
friend Iterator;
friend IterIter;
protected:
	Container();
public:
	MetaDef(Container);
	~Container();
	void InitNew();
	virtual int Capacity();
	bool assertclass(Class*);
	void InspectorId(char*, int);

	//---- comparison
	bool IsEqual(Object*);
	u_long Hash();

	//---- access
	int Size();
	bool IsEmpty();
	bool Contains(Object*);
	bool ContainsPtr(Object*);

	virtual Iterator *MakeIterator(bool dir= cIterForward, void *placement= 0);
	Iterator *MakeReversedIterator(void *placement= 0);
	virtual Object *AnyElement();   // return any element
	virtual Object *Find(Object*);  // returns 0 if not found, uses IsEqual
	virtual Object *FindPtr(Object*);       // returns 0 if not found, uses identity
	virtual int OccurrencesOf(Object*);     // uses IsEqual
	virtual int OccurrencesOfPtr(Object*);  // uses identity

	//---- object i/o
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);

protected:
	bool IsArgNull(char *where, Object *arg);
	bool CheckForIterator(char *where);
		
	//---- iterators
	bool HasIterators();
	void IteratorActivates(Iterator *which);
	void IteratorTerminates(Iterator *which);
	void DetachIterators();

	//---- robust iterators - place holder approach (old style)
	virtual void RemoveDeleted();
	void AnnounceRemove();
	bool HasDeletedObjects();

protected:
	int size;
	int nDeleted;       // for robust iterators (place holder approach)
	int iterCount;      // active iterators
private:
	Iterator iterHead;
public:
	void setCurrentContainer();             // for ForEach macro
	static Container *currentContainer;             // for ForEach macro
};

//---- Iter --------------------------------------------------------------------

class Iter {
	Iterator *seq;
	char space[64];
public:
	Iter(Container *coll, bool dir= cIterForward);
	Iter(Iterator *it);
	~Iter();
	Object *operator()();
	void Reset(Container *coll, bool dir= cIterForward);
	void Reset();
};

inline Iter::Iter(Container *coll, bool dir)
	{ seq= coll->MakeIterator(dir, space); }

inline Iter::Iter(Iterator *it)
	{ seq= it; }

inline Object *Iter::operator()()
	{ return (*seq)(); }

inline void Iter::Reset()
	{ seq->Reset(); }

//---- macros ------------------------------------------------------------------

#define ForEach(type,proc) \
setCurrentContainer(); \
Iter _NAME3_(type,proc,_next0)(Container::currentContainer); \
register type *_NAME3_(type,proc,_op0); \
while (_NAME3_(type,proc,_op0)= (type*) _NAME3_(type,proc,_next0)()) \
	_NAME3_(type,proc,_op0)->proc

#define _ForEach(type,proc,p) \
setCurrentContainer(); \
{ Iter _next(Container::currentContainer); \
register type *_op; \
while (_op= (type*) _next()) \
	if (p _op->IsKindOf(type)) \
		_op->proc; }

#define ForEachOfClass(type,proc) \
	_ForEach(type,proc,)
	
#define ForEachNotOfClass(type,proc) \
	_ForEach(type,proc,!)

//---- Container inlines -------------------------------------------------------

inline int Container::Size()
	{ return size - nDeleted; }

inline bool Container::IsEmpty()
	{ return (bool) (Size() <= 0); }

inline bool Container::Contains(Object *op)
	{ return Find(op) != 0; }

inline bool Container::ContainsPtr(Object *op)
	{ return FindPtr(op) != 0; }

inline Iterator *Container::MakeReversedIterator(void *placement)
	{ return MakeIterator(FALSE, placement); }

//---- inlines (protected and private) ----

inline void Container::setCurrentContainer()
	{ currentContainer= this; }

inline bool Container::IsArgNull(char *where, Object *arg)
	{ return arg ? FALSE : (Warning(where, cWarningNullArgument), TRUE); }

inline bool Container::HasIterators()
	{ return iterCount > 0; }

inline bool Container::CheckForIterator(char *where)
	{ return HasIterators() ? (Warning(where, cWarningActiveIterator), TRUE)
							: FALSE; }

inline void Container::AnnounceRemove()
	{ nDeleted++; }

inline bool Container::HasDeletedObjects()
	{ return (bool) (nDeleted > 0); }

#endif
